import { CSSProperties, ReactNode, ReactElement, DragEvent, PropsWithChildren } from 'react';
import TreeNode from './node';
import { AvailableVirtualListProps } from '../_class/VirtualList';
import { TreeNodeProps } from '.';

export type NodeInstance = ReactElement<PropsWithChildren<NodeProps>, typeof TreeNode>;
export type FakeNodeInstance = { key: string; props: TreeNodeProps };

export type SHOW_ALL = 'all';
export type SHOW_PARENT = 'parent';
export type SHOW_CHILD = 'child';

export type ActionOnClick = 'select' | 'check' | 'expand';

export interface TreeState {
  treeData?: TreeProps['treeData'];
  nodeList?: NodeProps[];
  shouldUpdate?: boolean;
  selectedKeys?: string[];
  checkedKeys?: string[];
  expandedKeys?: string[];
  loadedKeys?: string[];
  loadingKeys?: string[];
  halfCheckedKeys?: string[];
  // 当前正在展开/收起的key，是判定哪些节点需要执行动画的依据。
  currentExpandKeys?: string[];
}

export type FieldNamesType = {
  key?: string;
  title?: string;
  disabled?: string;
  children?: string;
  isLeaf?: string;
  disableCheckbox?: string;
  checkable?: string;
};

export type TreeDataType = NodeProps & {
  key?: string;
  _index?: number;
  children?: TreeDataType[];
  [key: string]: any;
};

export type AllowDrop = (options: {
  dropNode: NodeInstance;
  dragNode: NodeInstance | null;
  dropPosition: number;
}) => boolean;

/**
 * @title Tree
 */
export interface TreeProps {
  style?: CSSProperties;
  className?: string | string[];
  // 设置后开启虚拟滚动，已废弃，下一大版本移除
  height?: number;
  /**
   * @zh 不同尺寸
   * @en To set size
   */
  size?: 'mini' | 'small' | 'default' | 'large';
  /**
   * @zh 是否节点占据一行
   * @en Whether to occupy the remaining horizontal space
   */
  blockNode?: boolean;
  /**
   * @zh 是否自动展开父节点
   * @en Whether to automatically expand the parent node
   * @defaultValue true
   */
  autoExpandParent?: boolean;
  /**
   * @zh 是否支持多选
   * @en Whether to support multiple selection
   */
  multiple?: boolean;
  /**
   * @zh 是否在节点前添加选框
   * @en Whether to add a checkbox before the node
   */
  checkable?: boolean;
  /**
   * @zh 是否可拖拽
   * @en Whether the node can be dragged
   */
  draggable?: boolean;
  /**
   * @zh 是否开启展开收起的节点动画。
   * @en
   * @defaultValue true
   */
  animation?: boolean;
  /**
   * @zh 是否允许拖拽时放置在该节点。 (`dragNode` in `2.23.0`)
   * @en Whether to allow dropping on node. (`dragNode` in `2.23.0`)
   * @defaultValue () => true
   * @version 2.7.0
   */
  allowDrop?: AllowDrop;
  /**
   * @zh 是否可以选择
   * @en Whether can be selected
   * @defaultValue true
   */
  selectable?: boolean;
  /**
   * @zh 是否取消父子节点关联
   * @en Whether to cancel the parent-child association
   */
  checkStrictly?: boolean;
  /**
   * @zh
   * 定制回填方式 <br/> all: 返回所有选中的节点  <br/> parent: 父子节点都选中时只返回父节点 <br/> child: 只返回子节点
   * @en
   * Customize the return value <br/> all: Return all selected nodes  <br/> parent:
   * Only return the parent node when both parent and child nodes are selected <br/> child: Return only child nodes
   * @defaultValue all
   */
  checkedStrategy?: SHOW_ALL | SHOW_PARENT | SHOW_CHILD;
  /**
   * @zh 默认选中的树节点
   * @en The key of node selected by default
   */
  defaultSelectedKeys?: string[];
  /**
   * @zh 选中的树节点。（受控）
   * @en The key of the selected node(controlled)
   */
  selectedKeys?: string[];
  /**
   * @zh 默认选中复选框的树节点
   * @en The key of node checked by default
   */
  defaultCheckedKeys?: string[];
  /**
   * @zh 选中复选框的树节点。（受控）
   * @en The key of the checked node(controlled)
   */
  checkedKeys?: string[];
  /**
   * @zh 半选状态的节点.仅在 checkable 且 checkStrictly 时生效
   * @en the keys of half checked
   * @version 2.27.0
   */
  halfCheckedKeys?: string[];
  /**
   * @zh 默认展开的节点。
   * @en The key of node expanded by default
   */
  defaultExpandedKeys?: string[];
  /**
   * @zh 展开的节点，(受控)。
   * @en The key of the expanded node (controlled)
   */
  expandedKeys?: string[];
  /**
   * @zh 可以通过传入`treeData`,生成对应的树结构
   * @en The tree structure can be generated by passing in `treeData`
   */
  treeData?: TreeDataType[];
  /**
   * @zh 指定 key，title，isLeaf，disabled，children 对应的字段
   * @en Custom field name for key, title, isLeaf, disabled and children
   * @version 2.11.0
   */
  fieldNames?: FieldNamesType;
  /**
   * @zh 定制节点图标
   * @en Customize node icon
   * @defaultValue FieldNamesType
   * @version 2.9.0
   */
  icons?:
    | ((nodeProps: NodeProps) => {
        dragIcon?: ReactNode;
        switcherIcon?: ReactNode;
        loadingIcon?: ReactNode;
      })
    | {
        dragIcon?: ReactNode;
        switcherIcon?: ReactNode;
        loadingIcon?: ReactNode;
      };
  /**
   * @zh 传递虚拟列表属性，传入此参数以开启虚拟滚动
   * @en Pass the virtual-list properties, pass in this parameter to turn on virtual scrolling
   * @version 2.11.0
   */
  virtualListProps?: AvailableVirtualListProps;
  /**
   * @zh 渲染额外节点
   * @en Render additional node
   */
  renderExtra?: (props: NodeProps) => ReactNode;
  /**
   * @zh 自定义 title 的渲染
   * @en Customize title rendering
   */
  renderTitle?: (props: NodeProps) => ReactNode;
  /**
   * @zh 是否展示连接线
   * @en Whether to display the connection line
   */
  showLine?: boolean;
  /**
   * @zh 点击节点时对应的操作，可以是选中，复选选中，展开/收起
   * @en The action when click node
   * @version select
   */
  actionOnClick?: ActionOnClick | ActionOnClick[];
  /**
   * @zh 异步加载数据的回调，返回一个 `Promise`。
   * @en Callback when loaded data asynchronously, returning a `Promise`.
   */
  loadMore?: (node: NodeInstance) => Promise<void>;
  /**
   * @zh 点击树节点的回调
   * @en Callback when selected node
   */
  onSelect?: (
    selectedKeys: string[],
    extra: {
      selected: boolean;
      selectedNodes: NodeInstance[];
      node: NodeInstance;
      e: Event;
    }
  ) => void;
  /**
   * @zh 点击树节点复选框的回调
   * @en Callback when checked node
   */
  onCheck?: (
    checkedKeys: string[],
    extra: {
      node: NodeInstance;
      checkedNodes: NodeInstance[];
      checked: boolean;
      halfCheckedKeys: string[];
      halfCheckedNodes: NodeInstance[];
      e: Event;
    }
  ) => void;
  /**
   * @zh 点击展开/关闭的回调
   * @en Callback when expanded or collapsed node
   */
  onExpand?: (
    expandedKeys: string[],
    exra?: { expanded: boolean; node: NodeInstance; expandedNodes: NodeInstance[] }
  ) => void;
  /**
   * @zh 节点开始拖拽的回调
   * @en Callback when the node starts dragging
   */
  onDragStart?: (e: DragEvent<HTMLSpanElement>, node: NodeInstance) => void;
  /**
   * @zh 节点结束拖拽的回调
   * @en Callback when the node ends drag
   */
  onDragEnd?: (e: DragEvent<HTMLSpanElement>, node: NodeInstance) => void;
  /**
   * @zh 节点被拖拽至可释放目标上时的回调
   * @en Callback when the node is dragged onto a valid target
   */
  onDragOver?: (e: DragEvent<HTMLSpanElement>, node: NodeInstance) => void;
  /**
   * @zh 节点离开可释放目标上时的回调
   * @en Callback when the node leaves a valid target
   */
  onDragLeave?: (e: DragEvent<HTMLSpanElement>, node: NodeInstance) => void;
  /**
   * @zh 节点在可释放目标上释放时的回调
   * @en Callback when the node is dropped on the valid target
   */
  onDrop?: (info: {
    e: DragEvent<HTMLSpanElement>;
    dragNode: NodeInstance | null;
    dropNode: NodeInstance | null;
    dropPosition: number;
  }) => void;
  filterNode?: (node: NodeProps) => boolean; // 仅提供给tree-select使用
  children?: ReactNode;
  onMouseDown?: (e) => void;
  // 提升性能
  __ArcoAdapterMode__?: boolean;
}

/**
 * @title Tree.Node
 */
export interface NodeProps {
  style?: CSSProperties;
  className?: string | string[];
  blockNode?: boolean;
  /**
   * @zh 该节点显示的标题
   * @en Title for node
   */
  title?: string | ReactNode;
  /**
   * @zh 是否允许选中
   * @en Whether it can be selected
   * @defaultValue true
   */
  selectable?: boolean;
  /**
   * @zh 是否禁用节点
   * @en Whether to disable node
   */
  disabled?: boolean;
  /**
   * @zh 是否禁用复选框
   * @en Whether to disable check
   */
  disableCheckbox?: boolean;
  /**
   * @zh 该节点个性化显示的图标
   * @en Custom icon
   */
  icon?: ReactNode;
  /**
   * @zh 是否显示多选框
   * @en Whether to show checkbox
   */
  checkable?: boolean;
  /**
   * @zh 是否是叶子节点。动态加载时有效
   * @en Is it a leaf node. Effective when loading dynamically
   */
  isLeaf?: boolean;
  /**
   * @zh 定制节点图标，优先级高于 Tree。同时设置 Tree 上的 icons 属性时候，将会进行合并。
   * @en Customize node icons, it have higher priority than Tree. When the icons property on the Tree is set at the same time, will be merged.
   */
  icons?: TreeProps['icons'];
  /**
   * @zh 当前节点是否可拖拽
   * @en Whether the current node can be dragged
   */
  draggable?: boolean;
  showLine?: boolean;
  checked?: boolean;
  selected?: boolean;
  parentKey?: string;
  pathParentKeys?: string[];
  indeterminated?: boolean;
  _key?: string;
  _level?: number;
  _lineless?: boolean[];
  visible?: boolean;
  selectedKeys?: string[];
  checkedKeys?: string[];
  expandedKeys?: string[];
  loading?: boolean;
  loaded?: boolean;
  autoExpandParent?: boolean;
  expanded?: boolean;
  childrenData?: NodeProps[];
  dataRef?: TreeDataType;
  loadMore?: (node: NodeProps) => void;
}
